// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraPlayerBotController.h"

#include "AbilitySystemComponent.h"
#include "AbilitySystemGlobals.h"
#include "Engine/World.h"
#include "GameFramework/PlayerState.h"
#include "GameModes/LyraGameMode.h"
#include "LyraLogChannels.h"
#include "Perception/AIPerceptionComponent.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraPlayerBotController) // 包含由UE生成的代码

class UObject;

/**
 * 构造函数。
 */
ALyraPlayerBotController::ALyraPlayerBotController(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	bWantsPlayerState = true; // 需要玩家状态
	bStopAILogicOnUnposses = false; // 取消控制时不停止AI逻辑
}

/**
 * 玩家状态队伍改变回调。
 */
void ALyraPlayerBotController::OnPlayerStateChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam)
{
	ConditionalBroadcastTeamChanged(this, IntegerToGenericTeamId(OldTeam), IntegerToGenericTeamId(NewTeam)); // 条件广播队伍改变
}

/**
 * 玩家状态改变回调。
 */
void ALyraPlayerBotController::OnPlayerStateChanged()
{
	// 空实现，供派生类实现而不需要挂钩所有其他事件
}

/**
 * 广播玩家状态改变。
 */
void ALyraPlayerBotController::BroadcastOnPlayerStateChanged()
{
	OnPlayerStateChanged(); // 调用玩家状态改变回调

	// 从旧玩家状态解绑（如果有）
	FGenericTeamId OldTeamID = FGenericTeamId::NoTeam; // 旧队伍ID
	if (LastSeenPlayerState != nullptr) // 如果最后看到的玩家状态存在
	{
		if (ILyraTeamAgentInterface* PlayerStateTeamInterface = Cast<ILyraTeamAgentInterface>(LastSeenPlayerState)) // 获取队伍代理接口
		{
			OldTeamID = PlayerStateTeamInterface->GetGenericTeamId(); // 获取旧队伍ID
			PlayerStateTeamInterface->GetTeamChangedDelegateChecked().RemoveAll(this); // 移除所有绑定
		}
	}

	// 绑定到新玩家状态（如果有）
	FGenericTeamId NewTeamID = FGenericTeamId::NoTeam; // 新队伍ID
	if (PlayerState != nullptr) // 如果玩家状态存在
	{
		if (ILyraTeamAgentInterface* PlayerStateTeamInterface = Cast<ILyraTeamAgentInterface>(PlayerState)) // 获取队伍代理接口
		{
			NewTeamID = PlayerStateTeamInterface->GetGenericTeamId(); // 获取新队伍ID
			PlayerStateTeamInterface->GetTeamChangedDelegateChecked().AddDynamic(this, &ThisClass::OnPlayerStateChangedTeam); // 绑定队伍改变事件
		}
	}

	// 广播队伍改变（如果确实改变）
	ConditionalBroadcastTeamChanged(this, OldTeamID, NewTeamID); // 条件广播队伍改变

	LastSeenPlayerState = PlayerState; // 更新最后看到的玩家状态
}

/**
 * 初始化玩家状态。
 */
void ALyraPlayerBotController::InitPlayerState()
{
	Super::InitPlayerState(); // 调用父类方法
	BroadcastOnPlayerStateChanged(); // 广播玩家状态改变
}

/**
 * 清理玩家状态。
 */
void ALyraPlayerBotController::CleanupPlayerState()
{
	Super::CleanupPlayerState(); // 调用父类方法
	BroadcastOnPlayerStateChanged(); // 广播玩家状态改变
}

/**
 * 玩家状态复制回调。
 */
void ALyraPlayerBotController::OnRep_PlayerState()
{
	Super::OnRep_PlayerState(); // 调用父类方法
	BroadcastOnPlayerStateChanged(); // 广播玩家状态改变
}

/**
 * 设置通用队伍ID。
 */
void ALyraPlayerBotController::SetGenericTeamId(const FGenericTeamId& NewTeamID)
{
	UE_LOG(LogLyraTeams, Error, TEXT("你不能在玩家机器人控制器(%s)上设置队伍ID；它由关联的玩家状态驱动"), *GetPathNameSafe(this)); // 输出错误日志
}

/**
 * 获取通用队伍ID。
 */
FGenericTeamId ALyraPlayerBotController::GetGenericTeamId() const
{
	if (ILyraTeamAgentInterface* PSWithTeamInterface = Cast<ILyraTeamAgentInterface>(PlayerState)) // 获取队伍代理接口
	{
		return PSWithTeamInterface->GetGenericTeamId(); // 返回队伍ID
	}
	return FGenericTeamId::NoTeam; // 返回无队伍
}

/**
 * 获取队伍索引改变委托。
 */
FOnLyraTeamIndexChangedDelegate* ALyraPlayerBotController::GetOnTeamIndexChangedDelegate()
{
	return &OnTeamChangedDelegate; // 返回队伍改变委托
}

/**
 * 服务器重启控制器。
 */
void ALyraPlayerBotController::ServerRestartController()
{
	if (GetNetMode() == NM_Client) // 如果在客户端
	{
		return;
	}

	ensure((GetPawn() == nullptr) && IsInState(NAME_Inactive)); // 确保没有控制角色且处于非活跃状态

	if (IsInState(NAME_Inactive) || (IsInState(NAME_Spectating))) // 如果处于非活跃状态或观察状态
	{
 		ALyraGameMode* const GameMode = GetWorld()->GetAuthGameMode<ALyraGameMode>(); // 获取游戏模式

		if ((GameMode == nullptr) || !GameMode->ControllerCanRestart(this)) // 如果游戏模式不存在或控制器不能重启
		{
			return;
		}

		// 如果仍然附加到角色，离开它
		if (GetPawn() != nullptr) // 如果控制角色存在
		{
			UnPossess(); // 取消控制
		}

		// 重新启用输入，类似于ClientRestart中的代码
		ResetIgnoreInputFlags(); // 重置忽略输入标志

		GameMode->RestartPlayer(this); // 重启玩家
	}
}

/**
 * 获取对其它角色的队伍态度。
 */
ETeamAttitude::Type ALyraPlayerBotController::GetTeamAttitudeTowards(const AActor& Other) const
{
	if (const APawn* OtherPawn = Cast<APawn>(&Other)) { // 如果其它角色是Pawn

		if (const ILyraTeamAgentInterface* TeamAgent = Cast<ILyraTeamAgentInterface>(OtherPawn->GetController())) // 获取队伍代理接口
		{
			FGenericTeamId OtherTeamID = TeamAgent->GetGenericTeamId(); // 获取其它队伍ID

			// 检查其它角色ID以定义态度
			if (OtherTeamID.GetId() != GetGenericTeamId().GetId()) // 如果队伍ID不同
			{
				return ETeamAttitude::Hostile; // 敌对
			}
			else // 如果队伍ID相同
			{
				return ETeamAttitude::Friendly; // 友好
			}
		}
	}

	return ETeamAttitude::Neutral; // 返回中立
}

/**
 * 更新队伍态度。
 */
void ALyraPlayerBotController::UpdateTeamAttitude(UAIPerceptionComponent* AIPerception)
{
	if (AIPerception) // 如果AI感知组件存在
	{
		AIPerception->RequestStimuliListenerUpdate(); // 请求刺激监听器更新
	}
}

/**
 * 取消控制时调用。
 */
void ALyraPlayerBotController::OnUnPossess()
{
	// 确保被取消控制的角色不会保留为我们ASC的头像角色
	if (APawn* PawnBeingUnpossessed = GetPawn()) // 获取被取消控制的角色
	{
		if (UAbilitySystemComponent* ASC = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(PlayerState)) // 获取技能系统组件
		{
			if (ASC->GetAvatarActor() == PawnBeingUnpossessed) // 如果头像角色是被取消控制的角色
			{
				ASC->SetAvatarActor(nullptr); // 设置头像角色为空
			}
		}
	}

	Super::OnUnPossess(); // 调用父类方法
}